home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2010 April
/
PCWorld0410.iso
/
hity wydania
/
Ubuntu 9.10 PL
/
karmelkowy-koliberek-desktop-9.10-i386-PL.iso
/
casper
/
filesystem.squashfs
/
usr
/
sbin
/
lm-profiler
< prev
next >
Wrap
Text File
|
2009-10-06
|
9KB
|
303 lines
#! /bin/sh
# This script assists you in achieving very high power savings on laptops.
# It can detect programs that perform regular, non-bursty disk operations,
# and network services that listen on external addresses. When started,
# lm-profiler will run for 10 minutes (or a configured number of minutes),
# after which it will provide a series of recommendations.
#
# It will try to find init scripts for any programs that it recommends for
# stopping, and it will ask if you want to place links to those scripts in
# /etc/laptop-mode/batt-stop, so that laptop mode tools will automatically
# stop those daemons when battery mode is detected.
#
#
# This script is a part of Laptop Mode Tools.
#
# Configuration options for this script can be found in
# /etc/laptop-mode/lm-profiler.conf.
#
# Maintainer: Bart Samwel (bart@samwel.tk)
# Adapted from initial version written by Jan Polacek (jerome@ucw.cz).
#
# Read configuration.
#
# Defaults
PROFILE_RUN_LENGTH=600
ACTIVITY_INTERVAL_MAX=150
ACTIVITY_INTERVAL_MIN=5
RECOMMEND_DEFAULT_SERVICES=1
DEFAULT_SERVICES="anacron cron atd"
DEF_IGNORE_PROGRAMS="pdflush journald XFree86 acpid apmd lm-profiler dmesg syslogd awk sed grep mc bc xfs cat diff uniq vi mv sort sleep"
IGNORE_PROGRAMS="$DEF_IGNORE_PROGRAMS"
RECOMMEND_NETWORK_SERVICES=1
DEF_IGNORE_NETWORK_SERVICES="perl" # Some daemons run on perl, not very informative
IGNORE_NETWORK_SERVICES="$DEF_IGNORE_NETWORK_SERVICES"
VERBOSE_OUTPUT=0
if [ -f /etc/laptop-mode/lm-profiler.conf ] ; then
. /etc/laptop-mode/lm-profiler.conf
fi
#
# Internal variables
#
DEBUG=0
######################################################################
if [ $DEBUG -eq 1 ]; then
set -eux
fi
if [ "$VERBOSE_OUTPUT" -eq 1 ] ; then
OUTPUT="/dev/stdout"
else
OUTPUT="/dev/null"
fi
if [ ! `id -u` -eq 0 ]; then
echo "Only root can run profiler."
exit 0
fi
WORKDIR=`mktemp -d -t lm-profiler.XXXXXX`
start_profiling(){
# Turn on disk access profilling
if [ -f /proc/sys/vm/block_dump ]; then
echo "1" > /proc/sys/vm/block_dump
else
echo "/proc/sys/vm/block_dump does not exist, exiting."
exit 1
fi
}
stop_profiling(){
# Turn off disk access profilling
echo "0" > /proc/sys/vm/block_dump
}
# Create a commandline for grep, checking for the presence of all
# strings in a space-separated list passed as the first parameter.
format_params(){
for PARAM in $1 ; do
echo -n "-e $PARAM "
done
}
# Detect all processes that have accessed the disk since the last
# invocation of dmesg. The results are written to files called
# "write_accesses_N" and "read_accesses_N", where N is the first
# parameter of this function.
process_dmesg_diff(){
LEFT="$WORKDIR/dmesg_prev"
RIGHT="$WORKDIR/dmesg_next"
dmesg > $RIGHT
if [ -s $LEFT ] && [ -s $RIGHT ]; then
# The following command is long and complicated. It does
# the following things, separately for READ and WRITE
# accesses:
# 1. Retrieve only new lines, using diff.
# 2. Drop the first line -- it is probably a truncated
# version of an earlier line.
# 3. Parse out the name of the process.
# 4. Filter out IGNORE_PROGRAMS.
# 5. Write process name to output.
diff -u $LEFT $RIGHT \
|grep '^+' \
|grep -o '[^[:space:]]*([0-9]*): WRITE' \
|sed '1d' \
|awk -v FS="(" '{print $1}' \
|grep -v `format_params "$IGNORE_PROGRAMS"` \
|sort \
|uniq \
> $WORKDIR/write_accesses_$1
diff -u $LEFT $RIGHT \
|grep '^+' \
|grep -o '[^[:space:]]*([0-9]*): READ' \
|sed '1d' \
|awk -v FS="(" '{print $1}' \
|grep -v `format_params "$IGNORE_PROGRAMS"` \
|sort \
|uniq \
> $WORKDIR/read_accesses_$1
mv $RIGHT $LEFT
WRITE_ACCESSES_FOUND=0
for ACCESS in $(cat $WORKDIR/write_accesses_$1) ; do
if [ $WRITE_ACCESSES_FOUND -eq 0 ] ; then
printf '\r \rWrite accesses at %d/%d in lm-profiler run:' "$1" "$PROFILE_RUN_LENGTH"
WRITE_ACCESSES_FOUND=1
fi
echo -n " $ACCESS"
done
if [ $WRITE_ACCESSES_FOUND -ne 0 ] ; then
echo ""
fi
READ_ACCESSES_FOUND=0
for ACCESS in $(cat $WORKDIR/read_accesses_$1) ; do
if [ $READ_ACCESSES_FOUND -eq 0 ] ; then
printf '\r \rRead accesses at %d/%d in lm-profiler run:' "$1" "$PROFILE_RUN_LENGTH"
READ_ACCESSES_FOUND=1
fi
echo -n " $ACCESS"
done
if [ $READ_ACCESSES_FOUND -ne 0 ] ; then
echo ""
fi
else
echo "No dmesg data found to profile, exiting."
exit 1
fi
}
# Attempt to find an init script for ithe process given as an argument
findinit(){
INITDIR=
if [ -d /etc/init.d ] ; then
INITDIR=/etc/init.d
elif [ -d /etc/rc.d/init.d ] ; then
INITDIR=/etc/rc.d/init.d
fi
if [ "$INITDIR" != "" ] ; then
INIT=`ls $INITDIR/ |grep ^$1$ |head -n 1`
if [ -z "$INIT" ]; then
INIT=`grep $1 $INITDIR/* |sed s/:.*// |head -n 1`
else
INIT="$INITDIR/$INIT"
fi
if [ ! -z "$INIT" ] && [ -x $INIT ]; then
echo "$INIT"
fi
fi
}
# Look for names of running network services
profilenet(){
netstat -anp |grep ^tcp.*LISTEN |grep -v "Program name" |awk -v FS="/" '{print $2}' |sort |uniq |\
tr -d ['(',')','[',']']
}
#
# PROFILING RUN
#
# Disable profiling if the script gets interrupted.
trap "stop_profiling; echo; exit 10" EXIT HUP INT ABRT QUIT SEGV TERM
SECONDS_DONE=
echo "Profiling run started."
dmesg > $WORKDIR/dmesg_prev
start_profiling
echo > $WORKDIR/write_accesses_$SECONDS_DONE
echo > $WORKDIR/read_accesses_$SECONDS_DONE
SECONDS_DONE=0
while [ $SECONDS_DONE -le $PROFILE_RUN_LENGTH ] ; do
printf '\r%d seconds elapsed, %d remaining. \b\b\b\b\b\b\b\b\b' "$SECONDS_DONE" "$(($PROFILE_RUN_LENGTH - $SECONDS_DONE))"
sleep 1
SECONDS_DONE=$(($SECONDS_DONE + 1))
process_dmesg_diff $SECONDS_DONE
done
printf '\r \r'
stop_profiling
NETPROFILE=`profilenet`
echo "Profiling run completed."
#
# OUTPUT
#
ALREADY_SEEN=
if [ "$RECOMMEND_DEFAULT_SERVICES" -ne 0 ] ; then
for SERVICE in $DEFAULT_SERVICES ; do
echo
echo "Program: \"$SERVICE\""
echo "Reason: standard recommendation (program may not be running)"
INIT=`findinit $SERVICE`
if [ "$INIT" = "" ] ; then
echo "Init script: none"
echo "If you want to disable this program, you should do so manually."
else
echo "Init script: $INIT (GUESSED)"
echo
echo -n "Do you want to disable this service in battery mode? [y/N]: "
read ANSWER
if ( echo "$ANSWER" | grep -i ^y > /dev/null ) ; then
ln -fs $INIT /etc/laptop-mode/batt-stop/`echo $INIT | sed 's/.*\///g'`
fi
fi
ALREADY_SEEN="$ALREADY_SEEN $SERVICE"
done
fi
if [ "$RECOMMEND_NETWORK_SERVICES" -ne 0 ] ; then
for SERVICE in $NETPROFILE ; do
if ( echo " $IGNORE_NETWORK_SERVICES " | grep -v " $SERVICE " > /dev/null ) ; then
echo
echo "Program: \"$SERVICE\""
echo "Reason: listens on network, may not be needed offline."
INIT=`findinit $SERVICE`
if [ "$INIT" = "" ] ; then
echo "Init script: none"
echo "If you want to disable this program, you should do so manually."
else
echo "Init script: $INIT (GUESSED)"
echo
echo -n "Do you want to disable this service in battery mode? [y/N]: "
read ANSWER
if ( echo "$ANSWER" | grep -i ^y > /dev/null ) ; then
ln -fs $INIT /etc/laptop-mode/batt-stop/`echo $INIT | sed 's/.*\///g'`
fi
fi
ALREADY_SEEN="$ALREADY_SEEN $SERVICE"
fi
done
fi
SECONDS_LEFT=$PROFILE_RUN_LENGTH
while [ $SECONDS_LEFT -gt 0 ] ; do
for SERVICE in `cat $WORKDIR/*_accesses_$SECONDS_LEFT` ; do
if ( echo " $ALREADY_SEEN " | grep -v " $SERVICE " > /dev/null ) ; then
CUR_COMPARE_SECONDS=$(($SECONDS_LEFT - $ACTIVITY_INTERVAL_MIN))
while [ $CUR_COMPARE_SECONDS -gt $(($SECONDS_LEFT - $ACTIVITY_INTERVAL_MAX)) -a $CUR_COMPARE_SECONDS -gt 0 ] ; do
if ( grep "^$SERVICE$" $WORKDIR/*_accesses_$CUR_COMPARE_SECONDS > /dev/null ) ; then
if ( echo " $ALREADY_SEEN " | grep -v " $SERVICE " > /dev/null ) ; then
echo
echo "Program: \"$SERVICE\""
echo "Reason: disk access."
INIT=`findinit $SERVICE`
if [ "$INIT" = "" ] ; then
echo "Init script: none"
echo "If you want to disable this program, you should do so manually."
else
echo "Init script: $INIT (GUESSED)"
echo
echo -n "Do you want to disable this service in battery mode? [y/N]: "
fi
read ANSWER
if ( echo "$ANSWER" | grep -i ^y > /dev/null ) ; then
if [ -e $INIT ] ; then
ln -fs $INIT /etc/laptop-mode/batt-stop/`echo $INIT | sed 's/.*\///g'`
fi
fi
ALREADY_SEEN="$ALREADY_SEEN $SERVICE"
fi
fi
CUR_COMPARE_SECONDS=$(($CUR_COMPARE_SECONDS - 1))
done
fi
done
SECONDS_LEFT=$(($SECONDS_LEFT - 1))
done